package com.hxs.learn.aop;

import com.hxs.learn.common.exception.ServiceException;
import com.hxs.learn.common.result.Result;
import com.hxs.learn.common.web.LoginInfo;
import com.hxs.learn.common.web.utils.AjaxUtils;
import com.hxs.learn.common.web.utils.HttpKit;
import com.hxs.learn.common.web.utils.ShiroKit;
import com.hxs.learn.constants.core.web.ReqConst;
import com.hxs.learn.entity.sys.SysLog;
import com.hxs.learn.log.LogManager;
import com.hxs.learn.log.LogTaskFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 全局的的异常拦截器（拦截所有的控制器）（带有@RequestMapping注解的方法上都会拦截）
 *
 * @author huxinsheng
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    DefaultWebSecurityManager securityManager;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    GlobalExceptionHandler() {
        log.debug("GlobalExceptionHandler enable");
    }

    private void assertAjax(HttpServletRequest request, HttpServletResponse response) {
        if ((request.getHeader(ReqConst.REQ_HEADER) != null)
                && request.getHeader(ReqConst.REQ_HEADER).equalsIgnoreCase(ReqConst.REQ_XML_HTTP_REQUEST)) {
            // 如果是ajax请求响应头会有，x-requested-with
            // 在响应头设置session状态
            response.setHeader("sessionstatus", "timeout");
        }
    }

    /**
     * 无权访问该资源
     */
    @ExceptionHandler(AuthorizationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String credentials(AuthorizationException e, WebRequest request, HttpServletResponse response, Model model) {
        saveException(e);
        log.error("权限异常!", e);

        if (AjaxUtils.isAjaxRequest(request)) {
            // ajax 则返回json
            AjaxUtils.writeJson(Result.error(500, "无权限访问资源"), response);
        }
        model.addAttribute("error", "无权限访问资源");
        return "/_error/403";
    }

    /**
     * 拦截业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public String notFount(ServiceException e, WebRequest request, HttpServletResponse response, Model model) {
        saveException(e);
        log.error("业务异常:", e);

        if (AjaxUtils.isAjaxRequest(request)) {
            // ajax 则返回json
            AjaxUtils.writeJson(Result.error(500, e.getMessage()), response);
            return null;
        }
        model.addAttribute("error", e.getMessage());
        return "/_error/500";
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public String notFount(RuntimeException e, WebRequest request, HttpServletResponse response, Model model) {
        saveException(e);
        log.error("运行时异常:", e);

        if (AjaxUtils.isAjaxRequest(request)) {
            // ajax 则返回json
            AjaxUtils.writeJson(Result.error(500, e.getMessage()), response);
            return null;
        }
        model.addAttribute("error", e.getMessage());
        return "/_error/500";
    }

    private void saveException(RuntimeException e) {
        HttpServletRequest request = HttpKit.getRequest();
        String requestUrl = request.getServletPath();
        SysLog sysLog = new SysLog();

        sysLog.setTitle(e.getMessage());
        sysLog.setRequestUri(requestUrl);
        sysLog.setMethod(request.getMethod());
        sysLog.setRemoteAddr(request.getRemoteAddr());
        sysLog.setUserAgent(request.getHeader("user-agent"));

        SecurityUtils.setSecurityManager(securityManager);

        if (ShiroKit.isUser()) {
            if (null != ShiroKit.getUser()) {
                sysLog.setCreateBy(((LoginInfo) ShiroKit.getUser()).getLoginName());
            }
        } else {
            sysLog.setCreateBy("");
        }

        LogManager.me().executeLog(LogTaskFactory.exceptionLog(sysLog, e));
    }
}

